{--
        Esqueleto de programa para geração de bubble cloud em Haskell.
        Mais informações em: http://www.inf.ufsm.br/~andrea/elc117-2012b
--}


module Main where

import Text.Printf -- Oba, Haskell tem printf! :-)

type Point     = (Float,Float)
-- type Color     = (Int,Int,Int)
type Circle    = (Point,Float)

-- largura total da imagem
imageWidth :: Int
imageWidth = 500 -- 360

-- altura total da imagem
imageHeight :: Int
imageHeight = 500 -- 360


-- Funcao principal que faz leitura do dataset e gera arquivo SVG
main :: IO ()
main = do 
        strcontent <- readFile infile
        let pairs = map (span (/= ' ')) (lines strcontent)
            freqs = readInts (map snd pairs)
        writeFile outfile (svgCloudGen imageWidth imageHeight freqs)
        putStrLn "Ok!"
        where 
                infile = "dataset.txt"
                outfile = "tagcloud.svg"


-- Transforma lista de strings em lista de inteiros
readInts :: [String] -> [Int]
readInts ss = map read ss


-- Gera o documento SVG da tag cloud, concatenando cabecalho, conteudo e rodape
svgCloudGen :: Int -> Int -> [Int] -> String
svgCloudGen w h dataset = 
        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" ++ 
        "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" ++
        (svgViewBox w h) ++
        (concat (svgBubbleGen w h dataset)) ++ "</svg>\n"

-- #####################################################################################

{-
identico ao "t" da parametrizacao da espiral.
quando t = 0 cada circulo esta exatamente no centro da espiral.
a medida que ele cresce, cada circulo "caminha" sobre a espiral.
possui limite maximo, pois caso contrario extrapola imageWidth e imageHeight,
cortando os ultimos circulos. utilizando o geogebra verifiquei que 
como imageWidth = 500 e imageHeight = 500, t nao deve ser maior que 64*pi (ver geogebra)
-}
t :: Float
t = 0 -- 64*pi

-- valor fixo relativo a espiral, quanto maior, mais ela ficara enrolada e mais os circulos se aproximarao
v :: Float
v = 3.0

{-- 
coordenadas do centro de cada circulo (acompanham o movimento da espiral)
--}
xc :: Float
xc = fromIntegral imageWidth/2 + t*cos (v*t)

yc :: Float
yc = fromIntegral imageHeight/2 + t*sin (v*t)

-- lista de frequencias (dataset)
lisFreqAux :: [Int]
lisFreqAux = [2249, 480, 450, 409, 400]

-- converte lisFreq para valores Float
lisFreq :: [Float]
lisFreq = [ fromIntegral x | x <- lisFreqAux ]

-- recebe a lista de frequencias e retorna lista com o raio de cada circulo
-- lisRaios :: [Float] -> [Float]
-- lisRaios lisFreq = [ sqrt (x / sum lisFreq)*(fromIntegral (imageWidth*imageHeight)) | x <- lisFreq]
lisRaios :: [Float]
lisRaios = [ sqrt(((fromIntegral (imageWidth*imageWidth))*x)/((sum lisFreq)*4.0)) | x <- lisFreq ]


-- Esta funcao deve gerar a lista de circulos em formato SVG.
-- A implementacao atual eh apenas um teste que gera um circulo posicionado no meio da figura.
-- TODO: Alterar essa funcao para usar os dados do dataset.
svgBubbleGen:: Int -> Int -> [Int] -> [String]
-- fromIntegral faz aconversao de um valor inteiro para double
-- svgBubbleGen w h dataset = [svgCircle ((fromIntegral w/2, fromIntegral h/2), 10.0)]
svgBubbleGen w h dataset = [svgCircle ((xc, yc), head lisRaios)]

-- Gera string representando um circulo em SVG. A cor do circulo esta fixa. 
-- TODO: Alterar esta funcao para mostrar um circulo de uma cor fornecida como parametro.
svgCircle :: Circle -> String
svgCircle ((x,y),r) = printf "<circle cx=\"%f\" cy=\"%f\" r=\"%f\" fill=\"rgb(0,0,0)\" />\n" x y r

-- #####################################################################################

-- Configura o viewBox da imagem e coloca retangulo branco no fundo
svgViewBox :: Int -> Int -> String
svgViewBox w h =
        printf  "<svg width=\"%d\" height=\"%d\" viewBox=\"0 0 %d %d\"" w h w h ++ 
                " version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n" ++
        printf "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" style=\"fill:yellow;\"/>\n" w h